#include "./matrix_test.h"

TEST(Matrix1D, constructor_uint) {

	// Arrange
	Matrix1D *matrix = new Matrix1D( 1 );

	// Assert
	EXPECT_TRUE( matrix != NULL );

};

TEST(Matrix1D, constructor_copy) {

	// Arrange
	Matrix1D *matrix = new Matrix1D( 1 );
	*matrix, 2;

	// Act
	Matrix1D *copy = new Matrix1D( *matrix );

	// Assert
	EXPECT_TRUE( matrix != NULL );
	EXPECT_TRUE( copy != NULL );
	EXPECT_EQ( *matrix , *copy );

};

TEST(Matrix1D, getDim) {

	// Arrange
	Matrix1D *matrix = new Matrix1D( 3 );
	uint expected = 3;

	// Act
	uint actual = matrix->getDim();

	// Assert
	EXPECT_TRUE( matrix != NULL );
	EXPECT_EQ( expected, actual );

};

TEST(Matrix1D, operatorBrackets_uint) {

	// Arrange
	Matrix1D matrix( 3 );
	double expected = 3.0;

	// Act
	matrix[0] = expected;
	double actual = matrix[0];

	// Assert
	EXPECT_EQ( expected, actual );

};

TEST(Matrix1D, operatorBrackets_uint_exception) {

	// Arrange
	Matrix1D matrix( 3 );

	bool right_exception = false;

	// Act
	try {
		matrix[5];
	}
	catch( OutOfBoundsException ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, set_getValue) {

	// Arrange
	Matrix1D matrix( 3 );
	double expected = -3.0;

	// Act
	matrix.setValue( 0, expected );
	double actual = matrix.getValue( 0 );

	// Assert
	EXPECT_EQ( expected, actual );

};

TEST(Matrix1D, set_getSelection) {

	// Arrange
	Matrix1D matrix( 3 );
	Matrix1D expected( 2 );

	// Act
	for( usint i = 0; i < 2; ++i )
		expected[i] = 2.0;
	matrix.setSelection( 0, expected );
	Matrix1D actual( matrix.getSelection( 0, 2 ) );

	// Assert
	EXPECT_EQ( expected, actual );

};

TEST(Matrix1D, operatorAttribution) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, -3, -4.5, -0.75;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 3, 4, 5; final_mat2, 3, 4, 5;
	Matrix1D mat3(3), final_mat3(3);
	mat3, -3, -4.5, -0.75; final_mat3, -3, -4.5, -0.75;
	Matrix1D expected(3);
	expected, -3, -4.5, -0.75;

	// Act
	Matrix1D actual( ( ( mat1 = mat2 ) = mat3 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( mat3, final_mat3 ) << "mat3: " << mat3 << " | final_mat3: " << final_mat3 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorAttribution_exception) {

	// Arrange
	Matrix1D mat1(3);
	Matrix1D mat2(4);

	bool right_exception = false;

	// Act
	try {
		mat1 = mat2;
	}
	catch( IncompatibleMatrices1DException ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorAddition) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 3, 4, 5; final_mat2, 3, 4, 5;
	Matrix1D mat3(3), final_mat3(3);
	mat3, -3, -4.5, -0.75; final_mat3, -3, -4.5, -0.75;
	Matrix1D expected(3);
	expected, 0, 0.5, 6.25;

	// Act
	Matrix1D actual( ( ( mat1 + mat2 ) + mat3 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( mat3, final_mat3 ) << "mat3: " << mat3 << " | final_mat3: " << final_mat3 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorAddition_exception) {

	// Arrange
	Matrix1D mat1(3);
	Matrix1D mat2(4);

	bool right_exception = false;

	// Act
	try {
		mat1 + mat2;
	}
	catch( IncompatibleMatrices1DException ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorAdditionAndAttribution) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 0.5, 6.25;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 3, 4, 5; final_mat2, 3, 4, 5;
	Matrix1D mat3(3), final_mat3(3);
	mat3, -3, -4.5, -0.75; final_mat3, -3, -4.5, -0.75;
	Matrix1D expected(3);
	expected, 0, 0.5, 6.25;

	// Act
	Matrix1D actual( ( ( mat1 += mat2 ) += mat3 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( mat3, final_mat3 ) << "mat3: " << mat3 << " | final_mat3: " << final_mat3 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorAdditionAndAttribution_exception) {

	// Arrange
	Matrix1D mat1(3);
	Matrix1D mat2(4);

	bool right_exception = false;

	// Act
	try {
		mat1 += mat2;
	}
	catch( IncompatibleMatrices1DException ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorSubtraction) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 3, 4, 5; final_mat2, 3, 4, 5;
	Matrix1D mat3(3), final_mat3(3);
	mat3, -3, -4.5, -0.75; final_mat3, -3, -4.5, -0.75;
	Matrix1D expected(3);
	expected, 0, 1.5, -2.25;

	// Act
	Matrix1D actual( ( ( mat1 - mat2 ) - mat3 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( mat3, final_mat3 ) << "mat3: " << mat3 << " | final_mat3: " << final_mat3 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorSubtraction_exception) {

	// Arrange
	Matrix1D mat1(3);
	Matrix1D mat2(4);

	bool right_exception = false;

	// Act
	try {
		mat1 - mat2;
	}
	catch( IncompatibleMatrices1DException ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorSubtractionAndAttribution) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1.5, -2.25;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 3, 4, 5; final_mat2, 3, 4, 5;
	Matrix1D mat3(3), final_mat3(3);
	mat3, -3, -4.5, -0.75; final_mat3, -3, -4.5, -0.75;
	Matrix1D expected(3);
	expected, 0, 1.5, -2.25;

	// Act
	Matrix1D actual( ( ( mat1 -= mat2 ) -= mat3 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( mat3, final_mat3 ) << "mat3: " << mat3 << " | final_mat3: " << final_mat3 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorSubtractionAndAttribution_exception) {

	// Arrange
	Matrix1D mat1(3);
	Matrix1D mat2(4);

	bool right_exception = false;

	// Act
	try {
		mat1 -= mat2;
	}
	catch( IncompatibleMatrices1DException ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorMultiplication) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D expected(3);
	expected, 0, -3, -6;

	// Act
	Matrix1D actual( ( ( mat1 * 2.0 ) * -1.5 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorMultiplicationAndAttribution) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, -3, -6;
	Matrix1D expected(3);
	expected, 0, -3, -6;

	// Act
	Matrix1D actual( ( ( mat1 *= 2.0 ) *= -1.5 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorDivision) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D expected(3);
	expected, 0, -0.5, -1.0;

	// Act
	Matrix1D actual( ( ( mat1 / 2.0 ) / -1.0 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorDivision_exception) {

	// Arrange
	Matrix1D mat1(3);

	bool right_exception = false;

	// Act
	try {
		mat1 / 0.0;
	}
	catch( DivisionByZeroException<Matrix1D> ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorDivisionAndAttribution) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, -0.5, -1.0;
	Matrix1D expected(3);
	expected, 0, -0.5, -1.0;

	// Act
	Matrix1D actual( ( ( mat1 /= 2.0 ) /= -1.0 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorDivisionAndAttribution_exception) {

	// Arrange
	Matrix1D mat1(3);

	bool right_exception = false;

	// Act
	try {
		mat1 /= 0.0;
	}
	catch( DivisionByZeroException<Matrix1D> ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorEquals_true) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 0, 1, 2; final_mat2, 0, 1, 2;
	bool expected = true;

	// Act
	bool actual = ( mat1 == mat2 );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorEquals_false_dim) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(4), final_mat2(4);
	mat2, 0, 1, 2; final_mat2, 0, 1, 2;
	bool expected = false;

	// Act
	bool actual = ( mat1 == mat2 );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorEquals_false_value) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 0, 1, 4; final_mat2, 0, 1, 4;
	bool expected = false;

	// Act
	bool actual = ( mat1 == mat2 );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorDifferent_false) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 0, 1, 2; final_mat2, 0, 1, 2;
	bool expected = false;

	// Act
	bool actual = ( mat1 != mat2 );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorDifferent_true_dim) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(4), final_mat2(4);
	mat2, 0, 1, 2; final_mat2, 0, 1, 2;
	bool expected = true;

	// Act
	bool actual = ( mat1 != mat2 );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorDifferent_true_value) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	mat1, 0, 1, 2; final_mat1, 0, 1, 2;
	Matrix1D mat2(3), final_mat2(3);
	mat2, 0, 1, 4; final_mat2, 0, 1, 4;
	bool expected = true;

	// Act
	bool actual = ( mat1 != mat2 );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
	EXPECT_EQ( mat2, final_mat2 ) << "mat2: " << mat2 << " | final_mat2: " << final_mat2 << pendl;
	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorComma_double) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	final_mat1[0] = 1.0;
	final_mat1[1] = 2.0;
	final_mat1[2] = 3.5;
	Matrix1D expected(3);
	expected[0] = 1.0;
	expected[1] = 2.0;
	expected[2] = 3.5;

	// Act
	Matrix1D actual( ( mat1, 1.0, 2.0, 3.5 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
//	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

TEST(Matrix1D, operatorComma_double_exception) {

	// Arrange
	Matrix1D mat1(3);
	bool right_exception = false;

	// Act
	try {
		mat1, 0, 1, 2, 3, 4, 5;
	}
	catch( OutOfBoundsException ){
		right_exception = true;
	}
	catch( ... ){
		right_exception = false;
	}

	// Assert
	EXPECT_TRUE( right_exception );

};

TEST(Matrix1D, operatorComma_MatrixManipulation) {

	// Arrange
	Matrix1D mat1(3), final_mat1(3);
	final_mat1[0] = 1.0;
	final_mat1[1] = 0.0;
	final_mat1[2] = 3.5;
	Matrix1D expected(3);
	expected[0] = 1.0;
	expected[1] = 0.0;
	expected[2] = 3.5;

	// Act
	Matrix1D actual( ( mat1, 1.0, pr, 3.5 ) );

	// Assert
	EXPECT_EQ( mat1, final_mat1 ) << "mat1: " << mat1 << " | final_mat1: " << final_mat1 << pendl;
//	EXPECT_EQ( expected, actual ) << "expected: " << expected << " | actual: " << actual << pendl;

};

